﻿using System;
using System.IO;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using log4net;

namespace Pixster.Controllers.Helpers
{
    internal static class ImageLib
    {
        private static readonly ILog LOG = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        private const int THUMB_WIDTH = 200;
        private const int THUMB_HEIGHT = 150;
        
        public static void ResizeImage(string directory, string photoName)
        {
            try
            {
                var cacheDir = Path.Combine(directory, AppHelper.CacheDirctory);
                var thumbPath = Path.Combine(cacheDir, AppHelper.Thumbnail(photoName));

                if (File.Exists(thumbPath)) return;

                var imagePath = Path.Combine(directory, photoName);
                
                var stream = FixedSize(imagePath, THUMB_WIDTH, THUMB_HEIGHT, 90L);

                var stream2 = new FileStream(thumbPath, FileMode.Create);
                stream.WriteTo(stream2);
                stream2.Close();
                stream.Close();
            }
            catch (Exception ex)
            {
                LOG.ErrorFormat("Exception creating thumbnail image: '{0}', '{1}'.", directory, photoName, ex);
            }
        }

        private static ImageCodecInfo GetEncoderInfo(string mimeType)
        {
            var imageEncoders = ImageCodecInfo.GetImageEncoders();
            for (var i = 0; i < imageEncoders.Length; i++)
            {
                if (imageEncoders[i].MimeType == mimeType)
                {
                    return imageEncoders[i];
                }
            }
            return null;
        }

        private static Bitmap ImageResize(Bitmap sourceBitmap, int width, int height)
        {
            var image = new Bitmap(width, height);
            var graphics = Graphics.FromImage(image);
            graphics.CompositingQuality = CompositingQuality.HighQuality;
            graphics.SmoothingMode = SmoothingMode.AntiAlias;
            graphics.DrawImage(sourceBitmap, 0, 0, width, height);
            sourceBitmap.Dispose();
            graphics.Dispose();
            return image;
        }

        private static Bitmap ImageResize(string filename, int width, int height)
        {
            var sourceBitmap = new Bitmap(filename);
            return ImageResize(sourceBitmap, width, height);
        }

        private static MemoryStream ImageResize(string filename, int width, int height, long quality)
        {
            var sourceBitmap = new Bitmap(filename);
            if (height == 0)
            {
                height = Convert.ToInt16((width / ((float)sourceBitmap.Width)) * sourceBitmap.Height);
            }
            if (width == 0)
            {
                width = Convert.ToInt16((height / ((float)sourceBitmap.Height)) * sourceBitmap.Width);
            }
            var bitmap2 = ImageResize(sourceBitmap, width, height);
            var stream = new MemoryStream();
            var encoderInfo = GetEncoderInfo("image/jpeg");
            var encoder = Encoder.Quality;
            var encoderParams = new EncoderParameters(1);
            var parameter = new EncoderParameter(encoder, quality);
            encoderParams.Param[0] = parameter;
            bitmap2.Save(stream, encoderInfo, encoderParams);
            return stream;
        }


        private static MemoryStream FixedSize(string filename, int width, int height, long quality)
        {
            var sourceBitmap = new Bitmap(filename);
            var sourceWidth = sourceBitmap.Width;
            var sourceHeight = sourceBitmap.Height;
            const int sourceX = 0;
            const int sourceY = 0;
            var destX = 0;
            var destY = 0;

            float nPercent;

            var nPercentW = (width / (float)sourceWidth);
            var nPercentH = (height / (float)sourceHeight);

            //if we have to pad the height pad both the top and the bottom
            //with the difference between the scaled height and the desired height
            if (nPercentH < nPercentW)
            {
                nPercent = nPercentH;
                destX = (int)((width - (sourceWidth * nPercent)) / 2);
            }
            else
            {
                nPercent = nPercentW;
                destY = (int)((height - (sourceHeight * nPercent)) / 2);
            }

            var destWidth = (int)(sourceWidth * nPercent);
            var destHeight = (int)(sourceHeight * nPercent);

            LOG.InfoFormat("Resizing image for thumbnail, Filename: '{0}', Width: '{1}', Height: '{2}', Quality: '{3}'.",
                filename, destWidth, destHeight, quality);

            var bmPhoto = new Bitmap(width, height);//, PixelFormat.Format24bppRgb);
            bmPhoto.SetResolution(sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution);

            var grPhoto = Graphics.FromImage(bmPhoto);
            grPhoto.Clear(Color.Black);
            grPhoto.CompositingQuality = CompositingQuality.HighQuality;
            grPhoto.SmoothingMode = SmoothingMode.AntiAlias;

            grPhoto.DrawImage(sourceBitmap,
                              new Rectangle(destX, destY, destWidth, destHeight),
                              new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
                              GraphicsUnit.Pixel);

            grPhoto.Dispose();

            var stream = new MemoryStream();
            var encoderInfo = GetEncoderInfo("image/jpeg");
            var encoder = Encoder.Quality;
            var encoderParams = new EncoderParameters(1);
            var parameter = new EncoderParameter(encoder, quality);
            encoderParams.Param[0] = parameter;
            bmPhoto.Save(stream, encoderInfo, encoderParams);

            return stream;
        }
    }
}